class Hyperbox:
    def __init__(self, point,label,radius,max=np.inf,min=-np.inf):
        self.min_bound = np.maximum(np.array(point) - np.array(radius),min)
        self.max_bound = np.minimum(np.array(point) + np.array(radius),max)
        self.label = label

    def expand(self, other):
        self.min_bound = np.minimum(self.min_bound, other.min_bound)
        self.max_bound = np.maximum(self.max_bound, other.max_bound)

    def overlaps(self, other):
        return np.all(
            (self.min_bound < other.max_bound) & (self.max_bound > other.min_bound)
        )
    
    def __eq__(self,other):
        if isinstance(other, Hyperbox):
            return np.array_equal(self.min_bound, other.min_bound) and np.array_equal(self.max_bound, other.max_bound) and (self.label == other.label)
        return False
    
    def __hash__(self):
        return hash((tuple(self.min_bound), tuple(self.max_bound),self.label))
                                                  
    def fuzzify(self, point, gamma):
        term1 = np.maximum(0, 1 - np.maximum(0, gamma * np.minimum(1, point - self.max_bound)))
        term2 = np.maximum(0, 1 - np.maximum(0, gamma * np.minimum(1, self.min_bound - point)))
        sum_fuzziness = np.mean(term1 + term2,axis=-1)
        return sum_fuzziness